﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
namespace SPEasyCode
{
    /// <summary>
    /// Type hold all template process functions 
    /// </summary>
    public class TemplateProcesser
    {
        /// <summary>
        /// For each list loop
        /// </summary>
        /// <param name="filePath">file path</param>
        /// <param name="selectedLists">selected sharepoint lists</param>
        /// <param name="url">sharepoint site url</param>
        /// <param name="input">input text</param>
        public static void ForEachList(string filePath, List<string> selectedLists, string url, string input)
        {
            //Code runs under elevated privileges
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                //Open the site
                using (SPSite site = new SPSite(url))
                {
                    //Open the web
                    using (SPWeb web = site.OpenWeb())
                    {
                        //Initiate list start loop 
                        GlobalData.ListLoopStart = -1;

                        //Loop through all lists
                        foreach (string listName in selectedLists)
                        {
                            //Initiate list and other variables
                            SPList list = web.Lists[listName];
                            if (GlobalData.ListLoopStart == -1)
                                GlobalData.ListLoopStart = GlobalData.CurrentLine;

                            if (GlobalData.ListLoopStart > 0)
                                GlobalData.CurrentLine = GlobalData.ListLoopStart;

                            GlobalData.CurrentChildLine = 0;
                            GlobalData.Current_List_Name = list.Title;
                            GlobalData.Current_List_Internal_Name = list.Title;
                            GlobalData.Current_list = list;
                            string loopInstruction = string.Empty;

                            //Loop while Loop end instruction 
                            while (!LineProcesser.LoopEnd(loopInstruction))
                            {
                                //Increse line count for read
                                GlobalData.CurrentLine++;
                                //Read line form the file
                                loopInstruction = TemplateIO.ReadNextLine(GlobalData.CurrentLine, filePath);
                                //Set variables if there in the line
                                LineProcesser.SetVariable(ListLevelOperation(loopInstruction, false));
                                //Check for if condition
                                if (LineProcesser.IfCodition(loopInstruction))
                                {
                                    //If condition found
                                    IfCondition(filePath, loopInstruction, list);
                                }
                                else
                                {
                                    //No if condtion found
                                    //If not instruction process for out put file
                                    if (!LineProcesser.InstructionLine(loopInstruction))
                                        GlobalData.FinalOutPut.AppendLine(ListLevelOperation(loopInstruction, true));
                                    //Check for the for each field and if found pass to for foreach operation
                                    if (LineProcesser.InstructionLine(loopInstruction) && LineProcesser.ForeachField(loopInstruction))
                                        loopInstruction = ForEachField(filePath, list, loopInstruction);
                                }
                            }
                        }
                        GlobalData.ListLoopStart = -1;
                    }
                }
            });
        }

        /// <summary>
        /// List level key world replace
        /// </summary>
        /// <param name="loopInstruction">Current text</param>
        /// <param name="replaceVariableName">Replace variabale name or not</param>
        /// <returns>Processed text</returns>
        private static string ListLevelOperation(string loopInstruction, bool replaceVariableName)
        {
            //Get all key word replaced other than varibales
            string lineBefoerVariableNameReplace = LineProcesser.RemoveKeyWords(
                                                      LineProcesser.GetToLowerListName(
                                                      LineProcesser.GetListTitle(
                                                      LineProcesser.GetListGuid(
                                                      LineProcesser.GetListName(
                                                      loopInstruction, GlobalData.Current_List_Name), GlobalData.Current_list.ID.ToString()), GlobalData.Current_List_Name), GlobalData.Current_List_Name));
            if (replaceVariableName)
                //Peplace variables
                return    LineProcesser.ReplaceVariableName(lineBefoerVariableNameReplace);
            else
                //Dosen't replace variables
                return lineBefoerVariableNameReplace;
        }

        /// <summary>
        /// For each field loop
        /// </summary>
        /// <param name="filePath">File path</param>
        /// <param name="list">SharePoint list</param>
        /// <param name="loopInstruction">Current Line</param>
        /// <returns>Processed text</returns>
        public static string ForEachField(string filePath, SPList list, string loopInstruction)
        {
            //Initialze varables
            GlobalData.NextLine = GlobalData.CurrentLine - 1;
            //Loop through all fields in list
            foreach (SPField field in list.Fields)
            {
                //Reset varables
                GlobalData.LookupFieldListID = "";
                GlobalData.FieldChoiseValues = "";
                GlobalData.LookupFieldListTitle = "";

                if (GlobalData.NextLine < GlobalData.CurrentChildLine || GlobalData.NextLine == 0)
                    GlobalData.NextLine = GlobalData.CurrentChildLine;
                GlobalData.CurrentChildLine = GlobalData.CurrentLine - 1;

                //Get all fields in edit form to process
                if (field.CanBeDisplayedInEditForm == true)
                {
                    //Set additional infomation for lookup field
                    if (field.Type == SPFieldType.Lookup)
                    {
                        SPFieldLookup lkp = field as SPFieldLookup;
                        GlobalData.LookupFieldListID = lkp.LookupList;
                        SPList lookupList = list.ParentWeb.Lists[new Guid(lkp.LookupList)];
                        GlobalData.LookupFieldListTitle = lookupList.Title;
                    }
                    //Set additional infomation for choice field
                    else if (field.Type == SPFieldType.Choice)
                    {
                        SPFieldChoice choice = (SPFieldChoice)field;
                        string choices = "";
                        foreach (string cho in choice.Choices)
                        {
                            if (string.IsNullOrEmpty(choices))
                                choices = cho;
                            else
                                choices = string.Format("{0},{1}", choices, cho);
                        }

                        GlobalData.FieldChoiseValues = choices;
                    }
                    else if (field.Type == SPFieldType.Number)
                    {
                        SPFieldNumber numField = field as SPFieldNumber;
                        GlobalData.NumberFieldFormat = numField.DisplayFormat.ToString();
                    }
                    //Increse line count
                    GlobalData.CurrentChildLine++;
                    loopInstruction = string.Empty;
                    //loop until endloop key world found
                    while (!LineProcesser.LoopEnd(loopInstruction))
                    {
                        //Increse line count
                        GlobalData.CurrentChildLine++;
                        //Read line for process
                        loopInstruction = TemplateIO.ReadNextLine(GlobalData.CurrentChildLine, filePath);
                        //Set variables if any
                        LineProcesser.SetVariable(FieldLevelOperation(loopInstruction, field, false));
                        //Check for 
                        if (LineProcesser.IfCodition(loopInstruction))
                        {
                            IfCondition(filePath, loopInstruction,  field);

                        }
                        else
                        {
                            if (!LineProcesser.InstructionLine(loopInstruction))
                            {

                                GlobalData.FinalOutPut.AppendLine(
                                                           FieldLevelOperation(loopInstruction, field, true));
                            }
                        }
                    }
                }
            }
            GlobalData.CurrentLine = GlobalData.NextLine;
            GlobalData.NextLine = -1;
            loopInstruction = string.Empty;
            return loopInstruction;
        }


        /// <summary>
        /// Field level key word replace
        /// </summary>
        /// <param name="loopInstruction">Current text line</param>
        /// <param name="field">SharePoint Field</param>
        /// <param name="replaceVariable">Replace variabale name or not</param>
        /// <returns>Processed text</returns>
        private static string FieldLevelOperation(string loopInstruction, SPField field, bool replaceVariable)
        {
            string valueBeforeVariableReplace = LineProcesser.GetConvertType(
                                          LineProcesser.RemoveKeyWords(
                                          LineProcesser.GetToLowerListName(
                                          LineProcesser.GetListTitle(
                                          LineProcesser.GetListName(
                                          LineProcesser.GetDispalyName(
                                          LineProcesser.GetSPDataType(
                                          LineProcesser.GetDataType(
                                          LineProcesser.GetToLowerFieldName(
                                          LineProcesser.GetInternalFieldName(
                                          LineProcesser.GetRequiredField(
                                          LineProcesser.GetFieldLookupListTitle(
                                          LineProcesser.GetLookupListGuid(
                                          LineProcesser.GetFieldChoiseValues(
                                          LineProcesser.GetVariableName(
                                          LineProcesser.GetNumberFormat( loopInstruction, GlobalData.NumberFieldFormat ), field.Title).ToString(), GlobalData.FieldChoiseValues), GlobalData.LookupFieldListID)
                                          , GlobalData.LookupFieldListTitle), field.Required.ToString()), field.InternalName)
                                          , field.Title), field), field.Type.ToString()), field.Title)
                                          , GlobalData.Current_List_Name), GlobalData.Current_List_Internal_Name), GlobalData.Current_List_Name)), field);

            if (replaceVariable)
                return LineProcesser.ReplaceVariableName(valueBeforeVariableReplace);
            else
                return valueBeforeVariableReplace;
        }


        /// <summary>
        /// If condition for field level operations
        /// </summary>
        /// <param name="filePath">File path</param>
        /// <param name="line">Current Line</param>
        /// <param name="field">SharePoint Field</param>
        /// <returns></returns>
        public static string IfCondition(string filePath, string line,  SPField field)
        {

            string fieldName=field.Title;
            string fieldInternalName=field.InternalName;
            SPFieldType fieldType= field.Type;
            string loopInstruction = string.Empty;
            bool ok = true;
            bool condtionTure = false;
            bool elseCondition = false;
            bool elsePass = false;
            bool parentIf = true;
            GlobalData.IfIndex++;
            int openBreacketCount = 0;
            int closeBraketCount = 0;
            while (ok)
            {
                loopInstruction = TemplateIO.ReadNextLine(GlobalData.CurrentChildLine, filePath);

                if (LineProcesser.LoopStart(loopInstruction))
                    openBreacketCount++;
                if (LineProcesser.LoopEnd(loopInstruction))
                    closeBraketCount++;

                if (!parentIf && LineProcesser.IfCodition(loopInstruction) && condtionTure && !elsePass || !parentIf && LineProcesser.IfCodition(loopInstruction) && elseCondition && elsePass)
                {
                    GlobalData.IfConditionInfoCollection.Add(new IfConditionInfo(GlobalData.CurrentChildLine, GlobalData.IfIndex, condtionTure, elsePass, loopInstruction));
                    loopInstruction = IfCondition(filePath, loopInstruction,  field);
                    parentIf = true;
                }

                GlobalData.CurrentChildLine++;
                if (LineProcesser.IfCodition(loopInstruction) && parentIf || LineProcesser.IfCodition(loopInstruction) && condtionTure && !elsePass || LineProcesser.IfCodition(loopInstruction) && elseCondition && elsePass)
                {
                    loopInstruction = FieldLevelOperation(loopInstruction, field, true);

                    if (!condtionTure)
                        condtionTure = LineProcesser.IfCoditionTrue(loopInstruction);
                    if (!elseCondition)
                        elseCondition = !LineProcesser.IfCoditionTrue(loopInstruction);


                    parentIf = false;

                }
                else if (!LineProcesser.IfCodition(loopInstruction) && parentIf)
                {
                    if (GlobalData.IfConditionInfoCollection.Count > 0)
                    {
                        IfConditionInfo ifConditionInfon = GlobalData.IfConditionInfoCollection[GlobalData.IfConditionInfoCollection.Count - 1];
                        condtionTure = ifConditionInfon.IFPass;
                        elseCondition = !ifConditionInfon.IFPass;
                        elsePass = ifConditionInfon.ElseBranch;

                        GlobalData.IfConditionInfoCollection.Remove(ifConditionInfon);

                    }
                    parentIf = false;
                }

                if (!elsePass && openBreacketCount == closeBraketCount)
                    elsePass = LineProcesser.ElseCodition(loopInstruction);


                if (condtionTure && !elsePass)
                {
                    if (!LineProcesser.InstructionLine(loopInstruction))
                    {
                        GlobalData.FinalOutPut.AppendLine(FieldLevelOperation(loopInstruction, field, true));

                    }
                    LineProcesser.SetVariable(FieldLevelOperation(loopInstruction, field, false));
                    if (LineProcesser.ElseCodition(loopInstruction))
                        condtionTure = false;


                }
                else
                {
                    if (elseCondition && elsePass)
                    {
                        LineProcesser.SetVariable(FieldLevelOperation(loopInstruction, field, false));
                        if (!LineProcesser.InstructionLine(loopInstruction))
                        {
                            GlobalData.FinalOutPut.AppendLine(FieldLevelOperation(loopInstruction, field, true));

                        }
                        if (LineProcesser.LoopEnd(loopInstruction) && openBreacketCount == closeBraketCount)
                            elseCondition = false;


                    }


                }

                ok = !(elsePass && LineProcesser.LoopEnd(loopInstruction) && openBreacketCount == closeBraketCount);
            }
            //GlobalData.NextLine = GlobalData.NextLineIF;
            //GlobalData.CurrentChildLine = GlobalData.CurrentChildLineIF;
            GlobalData.CurrentChildLine--;
            return loopInstruction;
        }


        /// <summary>
        /// List level if condition
        /// </summary>
        /// <param name="filePath">File Path</param>
        /// <param name="line">Current Line</param>
        /// <param name="list">SharePoint List</param>
        /// <returns>Processed text</returns>
        public static string IfCondition(string filePath, string line, SPList list)
        {
            //if (!field.Hidden  &&  field.ShowInNewForm ==true  && field.Group == "Custom Columns")

            string loopInstruction = string.Empty;
            bool ok = true;
            bool condtionTure = false;
            bool elseCondition = false;
            bool elsePass = false;
            bool parentIf = true;
            GlobalData.IfIndex++;
            int openBreacketCount = 0;
            int closeBraketCount = 0;
            while (ok)
            {
                loopInstruction = TemplateIO.ReadNextLine(GlobalData.CurrentLine, filePath);
                LineProcesser.SetVariable(ListLevelOperation(loopInstruction, false));
                if (LineProcesser.ForeachField(loopInstruction) && condtionTure && !elsePass || LineProcesser.ForeachField(loopInstruction) && elseCondition && elsePass)
                {
                    ForEachField(filePath, list, loopInstruction);
                    loopInstruction = ">>>>";

                }

                if (LineProcesser.LoopStart(loopInstruction))
                    openBreacketCount++;
                if (LineProcesser.LoopEnd(loopInstruction))
                    closeBraketCount++;

                if (!parentIf && LineProcesser.IfCodition(loopInstruction) && condtionTure && !elsePass || !parentIf && LineProcesser.IfCodition(loopInstruction) && elseCondition && elsePass)
                {
                    GlobalData.IfConditionInfoCollection.Add(new IfConditionInfo(GlobalData.CurrentLine, GlobalData.IfIndex, condtionTure, elsePass, loopInstruction));
                    loopInstruction = IfCondition(filePath, loopInstruction, list);
                    parentIf = true;
                }

                GlobalData.CurrentLine++;


                if (LineProcesser.IfCodition(loopInstruction) && parentIf || LineProcesser.IfCodition(loopInstruction) && condtionTure && !elsePass || LineProcesser.IfCodition(loopInstruction) && elseCondition && elsePass)
                {
                    loopInstruction = ListLevelOperation(loopInstruction, true);

                    if (!condtionTure)
                        condtionTure = LineProcesser.IfCoditionTrue(loopInstruction);
                    if (!elseCondition)
                        elseCondition = !LineProcesser.IfCoditionTrue(loopInstruction);


                    parentIf = false;

                }
                else if (!LineProcesser.IfCodition(loopInstruction) && parentIf)
                {
                    if (GlobalData.IfConditionInfoCollection.Count > 0)
                    {
                        IfConditionInfo ifConditionInfon = GlobalData.IfConditionInfoCollection[GlobalData.IfConditionInfoCollection.Count - 1];
                        condtionTure = ifConditionInfon.IFPass;
                        elseCondition = !ifConditionInfon.IFPass;
                        elsePass = ifConditionInfon.ElseBranch;

                        GlobalData.IfConditionInfoCollection.Remove(ifConditionInfon);

                    }
                    parentIf = false;
                }

                if (!elsePass && openBreacketCount == closeBraketCount)
                    elsePass = LineProcesser.ElseCodition(loopInstruction);


                if (condtionTure && !elsePass)
                {
                    LineProcesser.SetVariable(ListLevelOperation(loopInstruction, false));
                    if (!LineProcesser.InstructionLine(loopInstruction))
                    {
                        GlobalData.FinalOutPut.AppendLine(ListLevelOperation(loopInstruction, true));

                    }
                    if (LineProcesser.ForeachField(loopInstruction))
                    {
                        GlobalData.FinalOutPut.AppendLine(ForEachField(filePath, list, loopInstruction));
                    }

                    if (LineProcesser.ElseCodition(loopInstruction))
                        condtionTure = false;


                }
                else
                {
                    if (elseCondition && elsePass)
                    {
                        LineProcesser.SetVariable(ListLevelOperation(loopInstruction, false));

                        if (!LineProcesser.InstructionLine(loopInstruction))
                        {
                            GlobalData.FinalOutPut.AppendLine(ListLevelOperation(loopInstruction, true));

                        }
                        if (LineProcesser.ForeachField(loopInstruction))
                        {
                            GlobalData.FinalOutPut.AppendLine(ForEachField(filePath, list, loopInstruction));
                        }
                        if (LineProcesser.LoopEnd(loopInstruction) && openBreacketCount == closeBraketCount)
                            elseCondition = false;


                    }


                }

                ok = !(elsePass && LineProcesser.LoopEnd(loopInstruction) && openBreacketCount == closeBraketCount);
            }
            //GlobalData.NextLine = GlobalData.NextLineIF;
            //GlobalData.CurrentChildLine = GlobalData.CurrentChildLineIF;
            GlobalData.CurrentLine--;
            return loopInstruction;
        }

        /// <summary>
        /// For each list loop
        /// </summary>
        /// <param name="filePath">File path</param>
        /// <param name="selectedLists">Selected SharePoint list names</param>
        /// <param name="url">SharePoint Site url</param>
        /// <returns>Processed text</returns>
        public static string ForeachList(string filePath, List<string> selectedLists, string url)
        {
            string input = TemplateIO.ReadNextLine(GlobalData.CurrentLine, filePath);

            if (LineProcesser.InstructionLine(input) && LineProcesser.ForeachList(input))
            {
                ForEachList(filePath, selectedLists, url, input);
            }

            else if (!LineProcesser.InstructionLine(input))
            {
                GlobalData.FinalOutPut.AppendLine(
                         LineProcesser.RemoveKeyWords(input
                        ));

                if (TemplateIO.LineCount(filePath) > GlobalData.CurrentLine + 1)
                {
                    GlobalData.CurrentLine++;
                    string line2 = TemplateIO.ReadNextLine(GlobalData.CurrentLine, filePath);
                    ForeachList(filePath, selectedLists, url);
                }
            }
            return GlobalData.FinalOutPut.ToString();
        }

        /// <summary>
        /// Main method call for Code generation
        /// </summary>
        /// <param name="filePath">File Path</param>
        /// <param name="selectedLists">SharePoint list names</param>
        /// <param name="url">SharePoint Site url</param>
        /// <returns>Fully Processed Code out put</returns>
        public static string GenerateCode(string filePath, List<string> selectedLists, string url)
        {

            TemplateProcesser.ForeachList(filePath, selectedLists, url);
            if (TemplateIO.LineCount(filePath) > GlobalData.CurrentLine + 1)
            {
                GlobalData.CurrentLine++;
                GenerateCode(filePath, selectedLists, url);
            }
            return GlobalData.FinalOutPut.ToString();
        }
    }


}
